package com.miracle.shiro.config;

import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.LinkedHashMap;

/**
 * @Author: rupert-tears
 * @Date: Created in 11:50 2021/7/16
 * @Description: 优秀的人都在孤独的翻山越岭！
 */
@Configuration
public class ShiroConfig {
    /**
     * 讲定义的 MyRealm 类定义到spring 的上下文容器中
     * @return 我们定义的 realm对象
     */
    @Bean
    public Realm myRealm(){
       return new MyRealm();
    }

    @Bean
    public SecurityManager securityManager (Realm myRealm){
        // web项目
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(myRealm);
        return securityManager;
    }

    @Bean
    public ShiroFilterFactoryBean filterFactoryBean(SecurityManager securityManager){
        ShiroFilterFactoryBean filterFactoryBean = new ShiroFilterFactoryBean();
        // 设置安全管理器
        filterFactoryBean.setSecurityManager(securityManager);
        // 设置如果用户没有登录后跳转的页面
        filterFactoryBean.setLoginUrl("/");
        // 设置登录成功后的跳转地址
        filterFactoryBean.setSuccessUrl("/success");
        // 设置没有操作后的跳转地址
        filterFactoryBean.setUnauthorizedUrl("/noperms");
        // 这里需要使用一个 LinkedHashMap 有顺序的Map
        LinkedHashMap<String,String> chain = new LinkedHashMap<>();
        // 配置/login 用户登录请求 不需要登录即可完成登录请求（否则用户将不能登录）
        chain.put("/login","anon");
        // 配置 /js 路径下的所有请求都不需要登录拦截
        chain.put("/js/**","anon");
        // 配置 /getRandomSalt 获取随机盐的请求不需要登录
        chain.put("/getRandomSalt","anon");
        // 设置 /admin/add 必须拥有admin：add 权限才可以访问
        // 注意：admin：add 仅仅是普通字符串 含义admin下的add 权限它就是一个权限编码 没有任何作用
         chain.put("/admin/add","authc,perms[admin:add]");
        // 配置 /logout 为登出请求 用户Shiro清空会话中的数据并自动返回为登录状态并跳转登录页面
        chain.put("/logout","logout");
        // 设置以下请求 必须登录之后才可以访问
        // roles[admin] 作用 用于指定以 /admin 开头的所有请求 必须要拥有admin的角色才可以访问
        chain.put("/admin/**","authc,roles[admin]");
        chain.put("/user/**","authc,roles[user]");
        // 设置所有请求必须登录之后才可以访问，因为范围较大所以要放在最后一个位置 （LinkHashMap）
        // 这里的拦截包括静态资源 如js css 等
        chain.put("/**","authc");
        filterFactoryBean.setFilterChainDefinitionMap(chain);
        return filterFactoryBean;
    }

    /**
     *
     * @return 激活Shiro标签
     */
    @Bean
    public ShiroDialect shiroDialect(){
        return new ShiroDialect();
    }

    /**
     * 开启Shiro的注解 （ @RequiresRoles @RequiresUser @RequiresPermissions ）
     * 需要借助SpringAOP来扫描这些注解
     * @param securityManager
     * @return
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager){
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }
}
